package herramientas;

public class MD5J {
	private static final int[]	 constante_ronda = { 7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23, 6, 10, 15, 21 };
	private static final int	 estado_inicial_a = 0x67452301;
	private static final int	 estado_inicial_b = 0xEFCDAB89;
	private static final int	 estado_inicial_c = 0x98BADCFE;
	private static final int	 estado_inicial_d = 0x10325476;
	private static final int[]	 S_BOX = { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
			0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e,
			0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
			0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942,
			0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
			0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7,
			0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
			0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 };
	 
	public static void main(String[] args) {
		String texto = "Amante: no me lleves, si muero, al camposanto A flor de tierra abre mi fosa, junto al riente, Juana de Ibarbourou";
		
		byte[] textobytes=texto.getBytes();
		int tamaobytes = textobytes.length;
		int numerobloques = ((tamaobytes + 8) / 64)+1;
		int tamaototal = numerobloques * 64;
		long tamaobits = (long) tamaobytes * 8;
		  
		byte[] relleno = new byte[tamaototal - tamaobytes];
		relleno[0] = (byte) 0x80;
		for (int i = 0; i < 8; i++)
		  { relleno[relleno.length - 8 + i] = (byte)tamaobits;
		    tamaobits = tamaobits/256;
		  }
		
		int a = estado_inicial_a;
		int b = estado_inicial_b;
		int c = estado_inicial_c;
		int d = estado_inicial_d;
		int[] temporal = new int[16];
 
		for (int i = 0; i < numerobloques; i++) {
			int indice = i * 64;
			for (int j = 0; j < 64; j++) {
				if (indice < tamaobytes)temporal[j / 4] = textobytes[indice] << 24 | (temporal[j / 4] >>> 8);	
				else 			 temporal[j / 4] = relleno[indice - tamaobytes] << 24 | (temporal[j / 4] >>> 8);

				indice++;
			}
	 
		    int estado_bloque_a = a;
		    int estado_bloque_b = b;
		    int estado_bloque_c = c;
		    int estado_bloque_d = d;
	
			int indicederonda = 0;
			int indiconstanteronda = 0;
			int cuartoconstantederonda = 0;
			int calculo = 0;

			for (int j = 0; j < 64; j++) {
				cuartoconstantederonda=(j & 3);
				int ronda = j / 16;
				switch (ronda) {
					case 0:	calculo = (b & c) | (~b & d);	indicederonda = j;			indiconstanteronda = cuartoconstantederonda; break;
					case 1:	calculo = (b & d) | (c & ~d);	indicederonda = (j * 5 + 1) & 0x0F;	indiconstanteronda= 4+cuartoconstantederonda;break;
					case 2:	calculo = b ^ c ^ d;	 	indicederonda = (j * 3 + 5) & 0x0F;	indiconstanteronda= 8+cuartoconstantederonda;break;
					case 3:	calculo = c ^ (b | ~d);  	indicederonda = (j * 7) & 0x0F;		indiconstanteronda=12+cuartoconstantederonda;break;
				}
				int temp = b +Integer.rotateLeft(a + calculo + temporal[indicederonda] + S_BOX[j], constante_ronda[indiconstanteronda]);
				a = d;
				d = c;
				c = b;
				b = temp;
			}
			
		    a = a + estado_bloque_a;
		    b = b + estado_bloque_b;
		    c = c + estado_bloque_c;
		    d = d + estado_bloque_d;
		}

		for (int k = 0; k < 4; k++) {
			int n = 0;
			
			switch (k) {
				case 0:	n = a;	break;
				case 1:	n = b;	break;
				case 2:	n = c;	break;
				case 3:	n = d;	break;
			}
			
			for (int j = 0; j < 4; j++) {
				System.out.print(String.format("%02X", (byte) n & 0xFF));
				n=(int)Math.floor(n/256.00);
			}
		}
	}
}